
#include <BStream>
#include <BHtmlItem>
#include <BSonNode>
#include "member_BSonDocument.h"
#include "member_BSonNode.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BSonNode*)_ptr)
#define member_allocate()		_ptr = new member_BSonNode(this)
#define member_release()		delete (member_BSonNode*)_ptr

BSonNode::BSonNode(BSonNode* parent)
{
	member_allocate();
	setParent(parent);
}
BSonNode::BSonNode(const BString& name, BSonNode* parent) : BObject(name)
{
	member_allocate();
	setParent(parent);
}
BSonNode::~BSonNode()
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BSonNode* child = member.children[i];
		son_member(child)->parent = 0;
	}
	member_release();
}

void BSonNode::copy(const BSonNode* other)
{
	this->setName(other->name());
	member.attribMap = son_member(other)->attribMap;
	member.format = son_member(other)->format;
	member.text = son_member(other)->text;
	for (int i = 0; i < son_member(other)->children.size(); i++)
	{
		BSonNode* node = son_member(other)->children[i];
		BSonNode* child = node->clone();
		son_member(this)->children.append(child);
	}
}
BSonNode* BSonNode::clone() const
{
	BSonNode* node = new BSonNode();
	node->copy(this);
	return node;
}

bool BSonNode::setFormat(const BString& format)
{
	if (member.format.text != format)
	{
		member.format.fromString(format);
		this->emit(Signal_FormatChanged, format);
		return true;
	}
	return true;
}
const BString& BSonNode::format() const
{
	return member.format.text;
}

void BSonNode::appendText(const BString& text)
{
	if (text.size())
	{
		member.text.append(text);
		this->emit(Signal_TextChanged, text);
	}
}
void BSonNode::prependText(const BString& text)
{
	if (text.size())
	{
		member.text.prepend(text);
		this->emit(Signal_TextChanged, text);
	}
}

bool BSonNode::setText(const BString& text)
{
	if (member.text != text)
	{
		member.text = text;
		this->emit(Signal_TextChanged, text);
	}
	return true;
}
const BString& BSonNode::text() const
{
	return member.text;
}

void BSonNode::setAttribMap(const BMap<BString, BString>& attribMap)
{
	if (member.attribMap != attribMap)
	{
		member.attribMap = attribMap;
		this->emit(Signal_AttribChanged);
	}
}
const BMap<BString, BString>& BSonNode::attribMap() const
{
	return member.attribMap;
}

bool BSonNode::setAttrib(const BString& name, const BString& value)
{
	if (name.empty())
		return false;
	BString& text = member.attribMap[name];
	if (text != value)
	{
		text = value;
		this->emit(Signal_AttribChanged, name);
	}
	return true;
}
const BString& BSonNode::attrib(const BString& name) const
{
	return member.attribMap(name);
}

bool BSonNode::containAttrib(const BString& name) const
{
	return member.attribMap.contain(name);
}
bool BSonNode::removeAttrib(const BString& name)
{
	return member.attribMap.remove(name);
}
void BSonNode::clearAttribs()
{
	if (member.attribMap.size())
	{
		member.attribMap.clear();
		this->emit(Signal_AttribChanged);
	}
}

const BSonDocument* BSonNode::document() const
{
	return member.document;
}
BSonDocument* BSonNode::document()
{
	return member.document;
}

const BSonNode* BSonNode::root() const
{
	const BSonNode* node = this;
	while (son_member(node)->parent)
		node = son_member(node)->parent;
	return node;
}
BSonNode* BSonNode::root()
{
	BSonNode* node = this;
	while (son_member(node)->parent)
		node = son_member(node)->parent;
	return node;
}

void BSonNode::setParent(BSonNode* parent)
{
	if (parent && parent != this)
	{
		parent->addChild(this);
	}
}
BSonNode* BSonNode::parent()
{
	return member.parent;
}
const BSonNode* BSonNode::parent() const
{
	return member.parent;
}
BSonNode* BSonNode::parent(const BString& name)
{
	if (name.empty())
		return 0;
	BSonNode* parent = member.parent;
	while (parent && parent->name() != name)
		parent = son_member(parent)->parent;
	return parent;
}
const BSonNode* BSonNode::parent(const BString& name) const
{
	if (name.empty())
		return 0;
	const BSonNode* parent = member.parent;
	while (parent && parent->name() != name)
		parent = son_member(parent)->parent;
	return parent;
}

BSonNode* BSonNode::addText(const BString& text)
{
	BSonNode* textNode = new BSonNode();
	textNode->setText(text);
	if (member.children.append(textNode))
	{
		son_member(textNode)->document = member.document;
		son_member(textNode)->parent = this;
		member.textDirty = true;
		return textNode;
	}
	return 0;
}
BSonNode* BSonNode::addChild(const BString& name, const BString& text)
{
	BSonNode* child = new BSonNode(name);
	member.children.append(child);
	son_member(child)->document = member.document;
	son_member(child)->parent = this;
	son_member(child)->text = text;
	member.textDirty = true;
	return child;
}
bool BSonNode::addChild(BSonNode* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (child == member.parent)
		return false;
	if (!member.children.contain(child))
	{
		member.children.append(child);
		if (son_member(child)->parent)
			son_member(child)->parent->remove(child);
		son_member(child)->document = member.document;
		son_member(child)->parent = this;
		object_member(child)->emit(Signal_ParentChanged, BValue(this, true));
		this->emit(Signal_Insert, BValue(child, this));
		return true;
	}
	return false;
}

BSonNode* BSonNode::insertText(int pos, const BString& text)
{
	BSonNode* textNode = new BSonNode();
	textNode->setText(text);
	if (member.children.insert(pos, textNode))
	{
		son_member(textNode)->document = member.document;
		son_member(textNode)->parent = this;
		member.raiseSignal(Signal_Changed);
		return textNode;
	}
	return 0;
}
BSonNode* BSonNode::insertChild(int pos, const BString& name, const BString& text)
{
	if (pos < 0 || pos > member.children.size())
		return 0;
	BSonNode* child = new BSonNode(name);
	child->setText(text);
	if (member.children.insert(pos, child))
	{
		son_member(child)->document = member.document;
		son_member(child)->parent = this;
		member.raiseSignal(Signal_Changed);
		return child;
	}
	return 0;
}
bool BSonNode::insertChild(int pos, BSonNode* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (child == member.parent)
		return false;
	if (son_member(child)->parent == this)
	{
		int index = member.children.find(child);
		member.children.move(index, pos);
		return true;
	}
	if (member.children.insert(pos, child))
	{
		if (son_member(child)->parent)
			son_member(child)->parent->removeChild(child);
		son_member(child)->parent = this;
		object_member(child)->emit(Signal_ParentChanged, BValue(this, true));
		this->emit(Signal_Insert, BValue(child, this));
		return true;
	}
	return false;
}

bool BSonNode::removeChild(int pos)
{
	if (member.children.check(pos))
	{
		BSonNode* child = member.children[pos];
		son_member(child)->document = 0;
		son_member(child)->parent = 0;
		BHolder<BSonNode> holder(child);
		member.children.remove(pos);
		member.raiseSignal(Signal_Remove, BValue(child, this));
		return true;
	}
	return false;
}
bool BSonNode::removeChild(const BString& name)
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BSonNode* child = member.children[i];
		if (child->name() == name)
		{
			removeChild(child);
			return true;
		}
	}
	return false;
}
bool BSonNode::removeChild(BSonNode* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (child == member.parent)
		return false;
	if (son_member(child)->parent != this)
		return false;
	BHolder<BSonNode> holder(child);
	son_member(child)->document = 0;
	son_member(child)->parent = 0;
	member.children.remove(child);
	this->emit(Signal_Remove, BValue(child, this));
	return true;
}

int BSonNode::childCount() const
{
	return member.children.size();
}
BSonNode* BSonNode::child(int index)
{
	return member.children(index);
}
const BSonNode* BSonNode::child(int index) const
{
	return member.children(index);
}

BSonNode* BSonNode::child(const BString& desc)
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (filter(child))
				return child;
		}
	}
	else
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (child->name() == desc)
				return child;
		}
	}
	return 0;
}
const BSonNode* BSonNode::child(const BString& desc) const
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (filter(child))
				return child;
		}
	}
	else
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (child->name() == desc)
				return child;
		}
	}
	return 0;
}

BSonNode* BSonNode::find(const BString& desc)
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		BSonNode* node = member.find(filter);
		return node;
	}
	else
	{
		if (this->name() == desc)
			return this;
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			BSonNode* node = child->find(desc);
			if (node)
				return node;
		}
	}
	return 0;
}
const BSonNode* BSonNode::find(const BString& desc) const
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			BSonNode* node = child->find(desc);
			if (node)
				return node;
		}
	}
	else
	{
		if (this->name() == desc)
			return this;
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			BSonNode* node = child->find(desc);
			if (node)
				return node;
		}
	}
	return 0;
}

bool BSonNode::setIndex(int index)
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& children = son_member(member.parent)->children;
		int pos = children.find(this);
		if (children.move(pos, index))
		{
			int end = bMax(pos, index);
			int pos = bMin(pos, index);
			for (int i = pos; i <= end; i++)
			{
				BSonNode* node = children[i];
				node->emit(Signal_OrderChanged, i);
			}
			return true;
		}
	}
	else
	{
		BArray<BSonNodeHolder>& nodes = sondoc_member(member.document)->nodes;
		int pos = nodes.find(this);
		if (nodes.move(pos, index))
		{
			int end = bMax(pos, index);
			int pos = bMin(pos, index);
			for (int i = pos; i <= end; i++)
			{
				BSonNode* node = nodes[i];
				node->emit(Signal_OrderChanged, i);
			}
			return true;
		}
	}
	return false;
}
int BSonNode::index() const
{
	if (BSonNode* parent = member.parent)
	{
		BArray<BSonNodeHolder>& children = son_member(parent)->children;
		return children.find(this);
	}
	if (BSonDocument* document = member.document)
	{
		BArray<BSonNodeHolder>& nodes = sondoc_member(document)->nodes;
		return nodes.find(this);
	}
	return -1;
}

bool BSonNode::raise()
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& children = son_member(member.parent)->children;
		int pos = children.find(this);
		if (children.move(pos, children.size() - 1))
		{
			for (int i = pos; i < children.size(); i++)
			{
				BSonNode* node = children[i];
				node->emit(Signal_OrderChanged, i);
			}
			return true;
		}
	}
	if (member.document)
	{
		BArray<BSonNodeHolder>& nodes = sondoc_member(member.document)->nodes;
		int pos = nodes.find(this);
		if (nodes.move(pos, nodes.size() - 1))
		{
			for (int i = pos; i < nodes.size(); i++)
			{
				BSonNode* node = nodes[i];
				node->emit(Signal_OrderChanged, i);
			}
			return true;
		}
	}
	return false;
}
bool BSonNode::lower()
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& children = son_member(member.parent)->children;
		int pos = children.find(this);
		if (children.move(pos, 0))
		{
			for (int i = 0; i <= pos; i++)
			{
				BSonNode* node = children[i];
				node->emit(Signal_OrderChanged, i);
			}
			return true;
		}
	}
	else
	{
		BArray<BSonNodeHolder>& nodes = sondoc_member(member.document)->nodes;
		int pos = nodes.find(this);
		if (nodes.move(pos, 0))
		{
			for (int i = 0; i <= pos; i++)
			{
				BSonNode* node = nodes[i];
				node->emit(Signal_OrderChanged, i);
			}
			return true;
		}
	}
	return false;
}

bool BSonNode::empty() const
{
	return member.text.empty() && member.attribMap.empty() && member.children.empty();
}
int BSonNode::level() const
{
	int count = 0;
	BSonNode* parent = member.parent;
	while (parent)
	{
		parent = son_member(parent)->parent;
		count++;
	}
	return count;
}

BSonNode* BSonNode::prev()
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& up_children = son_member(member.parent)->children;
		int index = up_children.find(this);
		if (index > 1)
			return up_children[index - 1];
	}
	return 0;
}
BSonNode* BSonNode::next()
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& up_children = son_member(member.parent)->children;
		int index = up_children.find(this);
		if (index < up_children.size() - 1)
			return up_children[index + 1];
	}
	return 0;
}

void BSonNode::remove(BSonNode* child)
{
	if (child && member.children.contain(child))
	{
		son_member(child)->parent = 0;
		member.children.remove(child);
	}
}
void BSonNode::remove(const BString& desc)
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (filter(child))
			{
				son_member(child)->parent = 0;
				member.children.remove(i--);
			}
		}
	}
	else
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (child->name() == desc)
			{
				son_member(child)->parent = 0;
				member.children.remove(i--);
			}
		}
	}
}
void BSonNode::clear()
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BSonNode* child = member.children[i];
		son_member(child)->parent = 0;
	}
	member.children.clear();
}

BSonNode* BSonNode::create(const BString& path)
{
	int end = path.find('/');
	if (end == path.size())
	{
		BSonNode* node = this->child(path);
		if (node == 0)
			node = this->addChild(path);
		return node;
	}
	BString text;
	path.substr(text, 0, end);
	BSonNode* node = this->child(text);
	if (node == 0)
	{
		node = this->addChild(text);
	}
	int pos = end + 1;
	while (node && pos < path.size())
	{
		end = path.find('/', pos);
		path.substr(text, pos, end);
		BSonNode* child = node->child(text);
		if (child == 0)
			child = node->addChild(text);
		node = child;
		pos = end + 1;
	}
	return node;
}

BSonNode* BSonNode::locate(const BString& desc)
{
	BStringArray namelst = desc.split('/');
	BSonNode* node = this->child(namelst.first());
	namelst.remove(0);
	while (node && namelst.size())
	{
		const BString& text = namelst.first();
		node = node->child(text);
		namelst.remove(0);
	}
	return node;
}
const BSonNode* BSonNode::locate(const BString& desc) const
{
	BStringArray namelst = desc.split('/');
	const BSonNode* node = this->child(namelst.first());
	namelst.remove(0);
	while (node && namelst.size())
	{
		const BString& text = namelst.first();
		node = node->child(text);
		namelst.remove(0);
	}
	return node;
}
